#include "LogUtil.h"
#include "StringUtil.h"
#include <mutex>
#include <condition_variable>
#include "PlatTlsUtil.h"
#include "../Core/CoreGlobals.h"
#include "FileUtil.h"


uint32 LogUtils::sTlsSlot = GetTlsSlot();

LogUtils& LogUtils::Get()
{
	LogUtils* logUtils = (LogUtils*)::TlsGetValue(sTlsSlot);
	if (logUtils == nullptr)
	{
		logUtils = new LogUtils;
	}
	return *logUtils;
}

LogUtils::LogUtils()
{
	// set tls bind this malloc chest
	assert(IsValidTlsSlot(sTlsSlot));
	::TlsSetValue(sTlsSlot, this);

#if RENDER_DOC 1
	if (IsInRenderThread())
	{
		std::string filename = FileUtil::GetAppPath() + std::string("\\render.log");
		outfile.open(filename.c_str(), std::ios::out | std::ios::app);
		outfile << " Render Log Begin \n";
	}
#endif
}

LogUtils::~LogUtils()
{
	assert(IsValidTlsSlot(sTlsSlot));
	::TlsFree(sTlsSlot);

#if RENDER_DOC 1
	if (IsInRenderThread())
	{
		outfile << " Render Log End ";
		outfile.flush();
		outfile.close();
	}
#endif
}


void LogUtils::LogFormat(const char* file, const char* func, int line, const TCHAR* szFormat, ...)
{
	va_list pArgList;
	va_start(pArgList, szFormat);
	_vsnwprintf_s(szBuffer, sizeof(szBuffer) / sizeof(TCHAR), szFormat, pArgList);
	va_end(pArgList);

	GetLocalTime(&st);

	wsprintf(szB2, TEXT("%02d:%02d:%02d.%03d [%d] [%s][%s][%d] %s \n"),
		st.wHour, st.wMinute, st.wSecond, st.wMilliseconds,
		GetCurrentProcessId(),
		UTF8_TO_TCHAR(file),
		UTF8_TO_TCHAR(func),
		line,
		szBuffer);

	OutputDebugString(szB2);

#if RENDER_DOC 1
	if (IsInRenderThread())
	{
		outfile << TCHAR_TO_UTF8(szB2);
		outfile << "\n";
		outfile.flush();
	}
#endif
}

/** Critical section for ThreadList */
//static std::mutex sLogCritical;
//
//void LogUtils(const char* file, const char* func, int line, const TCHAR* szFormat, ...)
//{
//	std::lock_guard<std::mutex> lk(sLogCritical);
//
//	static TCHAR szBuffer[2048];
//	static TCHAR szB2[2048];
//	static SYSTEMTIME st;
//
//	va_list pArgList;
//	va_start(pArgList, szFormat);
//	_vsnwprintf_s(szBuffer, sizeof(szBuffer) / sizeof(TCHAR), szFormat, pArgList);
//	va_end(pArgList);
//
//	GetLocalTime(&st);
//
//	wsprintf(szB2, TEXT("%02d:%02d:%02d.%03d [%d] [%s][%s][%d] %s \n"),
//		st.wHour, st.wMinute, st.wSecond, st.wMilliseconds,
//		GetCurrentProcessId(),
//		UTF8_TO_TCHAR(file),
//		UTF8_TO_TCHAR(func),
//		line,
//		szBuffer);
//
//	OutputDebugString(szB2);
//}

std::wstring MGUtils::ErrStr(VkResult errorCode)
{
	switch (errorCode) {
#define STR(r) case VK_ ##r: return L#r
		STR(SUCCESS);
		STR(NOT_READY);
		STR(TIMEOUT);
		STR(EVENT_SET);
		STR(EVENT_RESET);
		STR(INCOMPLETE);
		STR(ERROR_OUT_OF_HOST_MEMORY);
		STR(ERROR_OUT_OF_DEVICE_MEMORY);
		STR(ERROR_INITIALIZATION_FAILED);
		STR(ERROR_DEVICE_LOST);
		STR(ERROR_MEMORY_MAP_FAILED);
		STR(ERROR_LAYER_NOT_PRESENT);
		STR(ERROR_EXTENSION_NOT_PRESENT);
		STR(ERROR_FEATURE_NOT_PRESENT);
		STR(ERROR_INCOMPATIBLE_DRIVER);
		STR(ERROR_TOO_MANY_OBJECTS);
		STR(ERROR_FORMAT_NOT_SUPPORTED);
		STR(ERROR_FRAGMENTED_POOL);
		STR(ERROR_UNKNOWN);
		STR(ERROR_OUT_OF_POOL_MEMORY);
		STR(ERROR_INVALID_EXTERNAL_HANDLE);
		STR(ERROR_FRAGMENTATION);
		STR(ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS);
		STR(ERROR_SURFACE_LOST_KHR);
		STR(ERROR_NATIVE_WINDOW_IN_USE_KHR);
		STR(SUBOPTIMAL_KHR);
		STR(ERROR_OUT_OF_DATE_KHR);
		STR(ERROR_INCOMPATIBLE_DISPLAY_KHR);
		STR(ERROR_VALIDATION_FAILED_EXT);
		STR(ERROR_INVALID_SHADER_NV);
		STR(ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT);
		STR(ERROR_NOT_PERMITTED_EXT);
		STR(ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT);
		STR(THREAD_IDLE_KHR);
		STR(THREAD_DONE_KHR);
		STR(OPERATION_DEFERRED_KHR);
		STR(OPERATION_NOT_DEFERRED_KHR);
		STR(PIPELINE_COMPILE_REQUIRED_EXT);
		/*STR(ERROR_OUT_OF_POOL_MEMORY_KHR);
		STR(ERROR_INVALID_EXTERNAL_HANDLE_KHR);
		STR(ERROR_FRAGMENTATION_EXT);
		STR(ERROR_INVALID_DEVICE_ADDRESS_EXT);
		STR(ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS_KHR);
		STR(ERROR_PIPELINE_COMPILE_REQUIRED_EXT);*/
		STR(RESULT_MAX_ENUM);
#undef STR
	default:
		return L"UNKNOWN_ERROR";
	}
}

